package com.library.service.Impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.library.constant.MessageConstant;
import com.library.context.BaseContext;
import com.library.dto.*;
import com.library.entity.Book;
import com.library.entity.BookTag;
import com.library.entity.BrowseHistory;
import com.library.entity.Category;
import com.library.exception.BookNotFoundException;
import com.library.exception.DeletionNotAllowedException;
import com.library.mapper.*;
import com.library.result.PageResult;
import com.library.service.BookService;
import com.library.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
@Slf4j
public class BookServiceImpl implements BookService {

    @Autowired
    private BookMapper bookMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private BrowseHistoryMapper browseHistoryMapper;
    @Autowired
    private BorrowHistoryMapper borrowHistoryMapper;
    @Autowired
    private BookTagMapper bookTagMapper;

    @Override
    public void save(BookDTO bookDTO) {
        Book book = new Book();

        BeanUtils.copyProperties(bookDTO, book);

        book.setBorrowed(0);

        bookMapper.insert(book);
    }

    @Override
    public PageResult pageQuery(BookPageQueryDTO bookPageQueryDTO) {
        PageHelper.startPage(bookPageQueryDTO.getPage(),bookPageQueryDTO.getPageSize());
        Page<BookPageVO> page = bookMapper.pageQuery(bookPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());
    }


    @Override
    public void update(BookDTO bookDTO, Long id) {
        Book book = new Book();
        BeanUtils.copyProperties(bookDTO, book);
        book.setId(id);
        bookMapper.update(book);
    }

    @Override
    public void deleteById(Long id) {
        int count = bookMapper.getBorrowedBybookid(id);
        if(count > 0){
            throw new DeletionNotAllowedException(MessageConstant.BOOK_HAS_BEEN_BORROWED);
        }
        bookMapper.deleteById(id);
    }

    @Override
    public void deleteBatch(List<Long> ids) {
        log.info("批量删除书籍，ids:{}",ids);

        for(Long id : ids){
            int count = bookMapper.getBorrowedBybookid(id);
            if(count > 0){
                throw new DeletionNotAllowedException(MessageConstant.BOOK_HAS_BEEN_BORROWED);
            }
            bookMapper.deleteById(id);
        }
    }

    @Override
    public BookVO getBookDetailedById(Long id) {
        Book book = bookMapper.getBookByBookId(id);
        if(book == null){
            throw new BookNotFoundException(MessageConstant.BOOK_NOT_EXIST);
        }
        //对象属性拷贝
        BookVO bookVO = new BookVO();
        BeanUtils.copyProperties(book,bookVO);
        //获得分类
        Category category = categoryMapper.getById(book.getCategoryId());
        bookVO.setCategory(category.getName());

        //获得当前用户id
        Long userId = BaseContext.getCurrentId();
        //增加浏览记录
        BrowseHistory browseHistory = BrowseHistory
                .builder()
                .userId(userId)
                .bookId(id)
                .categoryId(book.getCategoryId())
                .bookTitle(book.getTitle())
                .browseDate(LocalDateTime.now())
                .build();
        browseHistoryMapper.insert(browseHistory);

        return bookVO;
    }

    @Override
    public PageResult searchPageQuery(SearchPageDTO searchPageDTO) {
        PageHelper.startPage(searchPageDTO.getPage(),searchPageDTO.getPageSize());
        Page<BookPageVO> page = bookMapper.searchPageQuery(searchPageDTO);
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 智能推荐（基于用户浏览记录）
     * @param userId
     * @return
     */
    @Override
    public List<RecommendationsVO> getRecommendations(Long userId) {

        List<RecommendationsVO> recommendations = null;
        List<Long> recommendationsIds = null;
        //获取用户的浏览记录
        List<Long> bookIds = browseHistoryMapper.getBookIdsByUserId(userId);
        List<Long> categoryIds = browseHistoryMapper.getCategoryIdsByUserId(userId);
        if(categoryIds != null && categoryIds.size() > 0){
            // 创建一个 HashMap 用于存储每个 categoryId 及其出现的次数
            Map<Long, Long> idCountMap = new HashMap<>();
            // 遍历 categoryIds 列表
            for (Long categoryId : categoryIds) {
                // 使用 getOrDefault 方法获取当前 categoryId 的计数，如果不存在则默认为 0
                Long count = idCountMap.getOrDefault(categoryId, 0L);
                // 将当前 categoryId 的计数加 1
                idCountMap.put(categoryId, count + 1);
            }
            // 将 idCountMap 排序
            List<Map.Entry<Long, Long>> sortedEntries = idCountMap.entrySet().stream()
                    .sorted(Map.Entry.comparingByValue(Long::compareTo))
                    .toList();
            // 将 categoryIds 集合清空
            categoryIds.clear();
            // 将 sortedEntries 前三个 categoryId 添加到 categoryIds 中
            for (int i = 0; i < Math.min(3, sortedEntries.size()); i++) {
                categoryIds.add(sortedEntries.get(i).getKey());
            }
            // 根据 categoryIds 查询推荐书籍Ids
            recommendationsIds = browseHistoryMapper.getRecommendationsBookIdsByCategoryIds(categoryIds);
            // 排除用户已经浏览的书籍
            recommendationsIds.removeAll(bookIds);

        }
        // 如果bookIdsByCategoryIds 为空，则推荐浏览记录高的
        if(recommendationsIds == null || recommendationsIds.size() < 10 ){
            Integer limit = 20;
            // 获取浏览记录前十的书籍
            List<BookCountByBrowseVO> bookCountByBrowse = bookMapper.getBookCountByBrowse(limit);
            if(recommendationsIds == null) recommendationsIds = new ArrayList<>();
            // 排除用户已经浏览的书籍
            for (BookCountByBrowseVO bookCountByBrowseVO : bookCountByBrowse) {
                Long bookId = bookCountByBrowseVO.getBookId();
                if(!bookIds.contains(bookId) && recommendationsIds.size() < 10){
                    recommendationsIds.add(bookId);
                }
            }

        }
        // 根据 bookIds 查询推荐书籍
        recommendations = bookMapper.getRecommendationsByBookIds(recommendationsIds);


        return recommendations;
    }

    @Override
    public void addTag(Long bookId, BookTagDTO bookTagDTO) {
        BookTag bookTag = new BookTag();
        BeanUtils.copyProperties(bookTagDTO, bookTag);
        bookTag.setBookId(bookId);
        if(bookTagDTO.getUserId() == null){
            bookTag.setUserId(BaseContext.getCurrentId());
        }
        bookTagMapper.insert(bookTag);

    }


    @Override
    public void updateTag(Long tagId, BookTagDTO bookTagDTO) {
        BookTag bookTag = new BookTag();
        BeanUtils.copyProperties(bookTagDTO, bookTag);
        bookTag.setId(tagId);
        bookTagMapper.update(bookTag);
    }

    @Override
    public List<BookTagVO> getTags(Long bookId) {
        //获得当前用户id
        Long userId = BaseContext.getCurrentId();
        List<BookTagVO> bookTags = bookTagMapper.getTags(bookId, userId);
        return bookTags;
    }

    @Override
    public PageResult searchTags(PageQueryDTO pageQueryDTO, String keyword) {
        PageHelper.startPage(pageQueryDTO.getPage(), pageQueryDTO.getPageSize());
        Page<BookTagVO> page = bookTagMapper.searchTags(keyword);
        return new PageResult(page.getTotal(), page.getResult());
    }

    @Override
    public BookVO getBooksByTagId(Long tagId) {
        Book book = bookMapper.getBookByTagId(tagId);
        BookVO bookVO = new BookVO();
        BeanUtils.copyProperties(book, bookVO);
        Category category = categoryMapper.getById(book.getCategoryId());
        bookVO.setCategory(category.getName());
        return bookVO;
    }

    @Override
    public void deleteTag(Long bookId, Long tagId) {
        bookTagMapper.deleteById(bookId,tagId);
    }


}
